#ifndef FILE_NODE_H
#define FILE_NODE_H

#include <memory>
#include <string>

#include <unistd.h>
#include <sys/stat.h>
#include <unordered_map>

#include "types.h"
#include "bigBuffer.h"
#include "dataNode.h"

class FileNode
{
    friend class FuseVMData;

private:
    int64_t _id;
    std::shared_ptr<DataNode> _data;
    nlink_t _numDirLinks = 0;
    void parse_name();
    FileNode(const FileNode &);
    FileNode &operator=(const FileNode &);
    static const int64_t ROOT_NODE_INDEX, NEW_NODE_INDEX, TMP_DIR_INDEX;
    FileNode(const char *fname, int64_t id, std::shared_ptr<DataNode> data, const char *real_name = "", int real_file_type = TYPE_NONE, uint64_t real_file_size = 0, const std::vector<int>& real_file_vector = std::vector<int>(), const std::unordered_map<int, std::vector<DataSegment>>& cache = std::unordered_map<int, std::vector<DataSegment>>());

protected:
    static FileNode *createIntermediateDir(const char *fname);

public:
    static FileNode *createFile(const char *fname, uid_t owner, gid_t group, mode_t mode, dev_t dev = 0);
    bool is_dir() const;
    void detachChild (FileNode *child);
    void appendChild(FileNode *child);
    static FileNode *createRootNode();
    static FileNode *createDir(const char *fname, int64_t id, uid_t owner, gid_t group, mode_t mode);
    static  int open_disk_files(const char *real_name, std::vector<int>& fd_vector, std::vector<std::string>& cbt_vector);
    static std::vector<DataSegment> scan_file(std::string cbt_file);
    static FileNode *createNodeForExisting(const char *shortName, const char *fname, int64_t id, int type, struct stat fileStat);
    ~FileNode();
    void chmod(mode_t mode);
    inline mode_t mode() const
    {
        return _data->mode();
    }
    inline dev_t device() const
    {
        return _data->device();
    }
    void setTimes(const timespec &atime, const timespec &mtime);
    void setCTime (const timespec &ctime);
    inline struct timespec atime() const
    {
        return _data->atime();
    }
    inline struct timespec ctime() const
    {
        return _data->ctime();
    }
    inline struct timespec mtime() const
    {
        return _data->mtime();
    }
    void setUid(uid_t uid);
    void setGid(gid_t gid);
    inline uid_t uid() const
    {
        return _data->uid();
    }
    inline gid_t gid() const
    {
        return _data->gid();
    }
    uint64_t size() const;
    long use_count() const { return _data.use_count(); }
    nlink_t num_dir_links() const { return _numDirLinks; }
    const char *name;         // 只包含文件名或目录名，不包含路径
    std::string full_name;    // 相对挂载点全路径
    std::string _real_name;   // 运行程序前已存在的文件的绝对路径
    int _real_file_type;      // 运行程序前已存在的文件类型[普通文件|vsphere备份数据文件]
    uint64_t _real_file_size; // 运行程序前已存在的文件大小
    std::string _store_name;    // 存储临时写入数据的文件路径
    std::vector<int> _real_file_vector; //所有原始磁盘数据文件描述符
    std::unordered_map<int, std::vector<DataSegment>> _cache; //缓存数据段
    int _store_file;    // 存储临时写入数据的文件描述符
    nodelist_t childs;
    FileNode *parent;
    DataNode *data()
    {
        return _data.get();
    }
    inline std::string getParentName() const
    {
        if (name > full_name.c_str())
        {
            return std::string(full_name, 0, static_cast<size_t>(name - full_name.c_str() - 1));
        }
        else
        {
            return "";
        }
    }
    void rename (const char *new_name);
    int open();
    int read(char *buf, size_t size, size_t offset);
    int write(const char *buf, size_t size, size_t offset);
    int close();
    static FileNode *createSymlink(const char *fname);
    int truncate(size_t offset);
};
#endif